﻿using System;
using System.ServiceModel;
using System.Threading;
using Topshelf;
using WJP;
using WJP.Configuration;
using WJP.DataPortal.WCF;
using WJP.Logging;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            {
                Console.WriteLine(e.ExceptionObject?.ToString());
                LogManager.Logger.Fatal(e.ExceptionObject.ToString());
            };

            HostFactory.Run(x =>
            {
                x.Service<HostService>();
                x.SetServiceName(Configuration.ServiceName);
                x.SetDisplayName(Configuration.ServiceDisplayName);
                x.SetDescription(Configuration.ServiceDescription);
                x.StartAutomaticallyDelayed();
                x.RunAsLocalSystem();
                x.EnableServiceRecovery(e =>
                {
                    e.RestartService(0);
                    e.RestartService(0);
                    e.RestartService(0);

                    e.OnCrashOnly();
                    e.SetResetPeriod(1);
                });
                x.OnException(ex =>
                {
                    LogManager.Logger.Fatal("服务启动失败", ex);
                });
            });
        }
    }

    /// <summary>
    /// 服务
    /// </summary>
    public class HostService : ServiceControl
    {
        ServiceHost serviceHost;
        Timer timer;
        static readonly string localAddress = PlatformEnvironment.Configuration.Section.Server.Address;
        static ILogger logger = NullLogger.Instance;

        public bool Start(HostControl hostControl)
        {
            try
            {
                hostControl.RequestAdditionalTime(TimeSpan.FromSeconds(10));

                DomainApp app = DomainApp.Create();
                app.Startup();
                logger = LogManager.GetLogger<Program>();

                serviceHost = new ServiceHost(typeof(ServerPortal));
                serviceHost.Open();
                RegisterToRoutingService();

                Console.WriteLine("服务{0}启动成功".FormatArgs(localAddress));

                logger.InfoFormat("服务{0}启动成功", localAddress);
            }
            catch (Exception ex)
            {
                logger.Error("路由服务启动失败：", ex);
            }

            return true;
        }

        /// <summary>
        /// 注册路由服务
        /// </summary>
        void RegisterToRoutingService()
        {
            var config = PlatformEnvironment.Configuration;
            if (config != null)
            {
                timer = new Timer(RegisterToRoutingService, null, TimeSpan.Zero, TimeSpan.FromMinutes(config.Section.Server.ConnectPeriod));
            }
        }

        /// <summary>
        /// 注册路由服务
        /// </summary>
        /// <param name="state"></param>
        static void RegisterToRoutingService(object state)
        {
            var config = PlatformEnvironment.Configuration;
            var channel = new ChannelFactory<IHost>(config.Section.Server.MainHostEndpoint);

            foreach (AddressElement host in config.Section.Server.MainHostCollection)
            {
                try
                {
                    channel.CreateChannel(new EndpointAddress(host.BaseAddress)).RegisterHost(new SubHost
                    {
                        Address = config.Section.Server.Address,
                        Performance = config.Section.Server.Performance
                    });
                    logger.InfoFormat("服务{0}注册到{1}成功", localAddress, host.BaseAddress);
                    Console.WriteLine("服务{0}注册到{1}成功".FormatArgs(localAddress, host.BaseAddress));
                }
                catch (Exception ex)
                {
                    logger.ErrorFormat(ex, "服务{0}注册到{1}失败", localAddress, host.BaseAddress);
                    Console.WriteLine("服务{0}注册到{1}失败".FormatArgs(localAddress, host.BaseAddress) + ex);
                }
            }
        }

        public bool Stop(HostControl hostControl)
        {
            serviceHost.Close();
            logger.Info("停止服务...");
            return true;
        }
    }
}
